#ifndef ANDROID_SERVICE_HH
#define ANDROID_SERVICE_HH

/*
 * @file    android_service.h
 *
 * Created on: Mar 10, 2012
 * Authors: Zeddy Chirombe, Alex Drake 
 *          {i.z.chirombe, alex.drake}@wustl.edu
 *
 * This file carries our Linux/Android Bridge implementation. On the Linux
 * side, it relys on ROS message service as the communication medium to 
 * interact with all other nodes that wish to engage in voice aided 
 * Robot/Human iteraction. These nodes interested in Android services, must
 * subscribe to android topics, and must advertize their unique inbox where
 * responses will be send out. 
 *
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <map>


#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <android_service/storage_msgAction.h>
#include <android_service/android.h>
#include <actionlib/client/simple_action_client.h>
#include <iostream>

#include "android_service/android_message.h"

using namespace std;

extern int errno;
const int MAX_MSG_SIZE = 256;
const float ROS_SCAN_RATE = 1.5;

enum NetStatusCodes {
    SUCCESS = 0, /* keep going */
    ANDROID_TIMEOUT, /* Timeout, decide whether to keep waiting for abandon request*/
    ANDROID_READ_ERROR, /* can't read msg from android - */ 
    ANDROID_SEND_ERROR, /* can't send msg to android - */ 
    SOCKET_CLOSED, /* remote android server as died, change state to connect mode */
    MALFORMED_MSG /* Message Rejected, */
};

template<class T>
struct ptr_less
    : public binary_function<T, T, bool> {  
        bool operator()(const T& left, const T& right) const{
            return (left.message_priority() < right.message_priority());
        }
};

typedef actionlib::SimpleActionClient<android_service::storage_msgAction> Client;

class Android_Service
{
public:
    Android_Service(Client *client, string hostname, int port);
    ~Android_Service();

    int open();
    int init_vocabulary(string filename);
    int send_msg(Message *hMsg);
    int recv_msg(Message* hMsg, int timeout);
    int android_bio_action(Message& msg);
    int android_listener();
    int android_dispatcher();
    int send_bio_msg(Message *msg);
    int send_voice_msg(Message *msg);

    void showBiometrics(Message& msg);
    void voiceBox();
    void usage();
    string itos(int i);

    void android_packMsg(Message *androidMsg, android_service::android *rosMsg);
    void android_callback(const android_service::android& msg);

    static void *_android_listener_(void* This) {
	Android_Service *pthis = (Android_Service*)This;
	pthis->android_listener();
	return 0;
    }    
    static void *_android_dispatcher_(void* This) {
	Android_Service *pthis = (Android_Service*)This;
	pthis->android_dispatcher();
	return 0;
    }    
    static int message_counter;

private:
    // android stuff - 
    bool chanState;
    Client *client;
    string hostname;
    string bio_base_path;
    int sockfd, port, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[MAX_MSG_SIZE];

    char cwd_path[PATH_MAX];

    map<string, bool> harris_vocabulary;

    pthread_t 	    listener_thread;
    pthread_t 	    dispatcher_thread;
    pthread_cond_t  mqueue_cv; 
    pthread_mutex_t mqueue_mtx;
    deque<Message> msgQue;
    deque<Message> msgQueBio;

    bool bio_msg_pending;
    bool voice_msg_pending;
    struct timespec wait_to;

    // ros stuff -  
    ros::NodeHandle nh_;

    ros::Publisher android_voice_pub;
    ros::Publisher android_map_pub;
    ros::Subscriber android_sub;


};
#endif
